package adc.app.ui.wicket.model;

import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;

import adc.app.spec.IBo;
import adc.app.spec.IBoBs;


public class BoModel<T extends IBo> implements IModel<T> {
	
	private static final long serialVersionUID = 1L;
	
	private IModel<Long> domainObjectIdModel;
	IModel<? extends IBoBs<T>> bsModel;
	private transient T domainObject;
	private transient boolean attached;
	
    public static <T extends IBo, BS extends IBoBs<T>> BoModel<T> of(Class<BS> bsClass) {
        return new BoModel<T>(bsClass);
    }

    public static <T extends IBo, BS extends IBoBs<T>> BoModel<T> of(T bo, Class<BS> bsClass) {
        return new BoModel<T>(bo, bsClass);
    }
	
	public <BS extends IBoBs<T>> BoModel(IModel<Long> domainObjectIdModel, 
			IModel<BS> serviceModel) {
		this.domainObjectIdModel = domainObjectIdModel;
		this.bsModel = serviceModel;
	}
	
	public <BS extends IBoBs<T>> BoModel(IModel<Long> domainObjectIdModel, 
			Class<BS> businessServiceClass) {
		this(domainObjectIdModel, new SpringBeanModel<BS>(businessServiceClass));
	}
	
	public <BS extends IBoBs<T>> BoModel(Long domainObjectId, IModel<BS> serviceModel) {
		this(new Model<Long>(domainObjectId), serviceModel);
	}
	
	public <BS extends IBoBs<T>> BoModel(Long domainObjectId,
			Class<BS> businessServiceClass) {
		this(new Model<Long>(domainObjectId), businessServiceClass);
	}
	
	public <BS extends IBoBs<T>> BoModel(T domainObject, IModel<BS> serviceModel) {
		this(domainObject != null ? domainObject.getId() : null, serviceModel);
		if (domainObject != null) {
			this.domainObject = domainObject;
			this.attached = true;
		}
	}
	
	public <BS extends IBoBs<T>> BoModel(T domainObject, Class<BS> businessServiceClass) {
		this(domainObject, new SpringBeanModel<BS>(businessServiceClass));
	}
	
	public <BS extends IBoBs<T>> BoModel(Class<BS> businessServiceClass) {
        this((T) null, businessServiceClass);
    }

	@Override public T getObject() {
		if (!attached) {
			Long id = domainObjectIdModel.getObject();
			if (id == null) {
				domainObject = bsModel.getObject().create();
			} else {
				domainObject = bsModel.getObject().byId(domainObjectIdModel.getObject());
			}
			attached = true;
		}
		return domainObject;
	}

	@Override public void setObject(T object) {
		domainObject = object;
		domainObjectIdModel.setObject(domainObject.getId());
		attached = true;
	}

	@Override public void detach() {
		domainObject = null;
		attached = false;
		bsModel.detach();
		domainObjectIdModel.detach();
	}

}
